﻿using Sidvall.Data;
using Sidvall.LogManager.Data.Entity.Entities;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;

namespace Sidvall.LogManager.Data.Entity.Model.StorageManagers
{
    public static partial class LogScopeItemManager
    {
        #region Partial Members

        #region OnBeforeGetItems

        static partial void OnBeforeGetItems(StorageManager storageManager, Sidvall.Business.DataPortalContext<ILogScopeItem, FetchListCriteria<Fields.LogScopeItemField, Relations.LogScopeItemRelation>> dataPortalContext)
        {
            dataPortalContext.Tasks.Add(BeforeGetItemsAsync(storageManager, dataPortalContext));
        }

        #endregion

        #endregion
        #region Public Members

        #region BeforeGetItemsAsync

        public static async Task BeforeGetItemsAsync(StorageManager storageManager, Sidvall.Business.DataPortalContext<ILogScopeItem, Sidvall.Data.FetchListCriteria<Fields.LogScopeItemField, Relations.LogScopeItemRelation>> dataPortalContext)
        {
            switch (dataPortalContext.OperationContext.CriteriaId)
            {
                case Sidvall.LogManager.ParameterManager.GetEventItemsCriteriaId:
                    dataPortalContext.ResultValueListProvider = await GetItemsAsync(storageManager, dataPortalContext.OperationContext).ConfigureAwait(false);
                    dataPortalContext.Result = Sidvall.Business.DataPortalResult.Ok;
                    break;
                default:
                    break;
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region GetItemsAsync

        internal static async Task<Sidvall.Data.DataRowCollection<LogScopeItem>> GetItemsAsync(StorageManager storageManager, SortCriteriaBase<Sidvall.LogManager.Data.Fields.LogScopeItemField> criteria)
        {
            var items = new LogScopeItemCollection();
            var query = PrepareFilter(storageManager, criteria);
            if ((criteria.RowStartIndex > 0) || (criteria.RowCount > 0))
                items.TotalRowCount = query.Count();
            else
                items.TotalRowCount = null;
            query = PrepareSort(storageManager, criteria, query);
            if (criteria.RowStartIndex > 0)
                query = query.Skip(criteria.RowStartIndex.Value);
            if (criteria.RowCount > 0)
                query = query.Take(criteria.RowCount.Value);
            await Sidvall.LogManager.Data.Entity.SystemContext.Current.DataManager.LoadEntityObjectsAsync(query, items, DataRowState.Unchanged).ConfigureAwait(false);
            return items;
        }

        #endregion
        #region PrepareFilter

        internal static IQueryable<LogScopeItem> PrepareFilter(StorageManager storageManager, SortCriteriaBase<Sidvall.LogManager.Data.Fields.LogScopeItemField> criteria)
        {
            Sidvall.Logging.EventType? eventType;
            string category, textFilter;
            long? logScopeId;

            if (criteria.Parameters != null)
            {
                logScopeId = criteria.Parameters.ValueToNullableInt64(Data.Fields.LogScopeItemField.LogScopeId.ToString());
                eventType = criteria.Parameters.ValueToNullableEnum<Sidvall.Logging.EventType>(Data.Fields.LogScopeItemField.EventTypeId.ToString());
                category = criteria.Parameters.ValueToString(Data.Fields.LogScopeItemCategoryField.Category.ToString(), null);
                textFilter = criteria.Parameters.ValueToString(Data.Fields.LogScopeItemField.Message.ToString(), null);
            }
            else
            {
                logScopeId = null;
                eventType = null;
                category = null;
                textFilter = null;
            }
            var query = (from o in storageManager.ObjectContext.LogScopeItem.AsNoTracking()
                         select o);
            if (logScopeId != null)
            {
                query = (from o in query
                         where (o.LogScopeId == logScopeId.Value)
                         select o);
            }
            if (eventType != null)
            {
                var eventTypeId = (int)eventType.Value;
                query = (from o in query
                         where (o.EventTypeId == eventTypeId)
                         select o);
            }
            if (!string.IsNullOrWhiteSpace(category))
            {
                query = (from o in query
                         join m in storageManager.ObjectContext.LogScopeItemCategory on o.LogScopeItemId equals m.LogScopeItemId
                         where (m.Category.Equals(category, System.StringComparison.OrdinalIgnoreCase))
                         select o);
            }
            if (!string.IsNullOrWhiteSpace(textFilter))
            {
                query = (from o in query
                         where (o.Title.Contains(textFilter)) || (o.Message.Contains(textFilter))
                         select o);
            }
            query = Sidvall.LogManager.Data.Entity.SystemContext.Current.DataManager.PrepareFilter(query, criteria.Filter, GetFieldName);

            return query;
        }

        #endregion
        #region PrepareSort

        internal static IQueryable<LogScopeItem> PrepareSort(StorageManager storageManager, SortCriteriaBase<Sidvall.LogManager.Data.Fields.LogScopeItemField> criteria, IQueryable<LogScopeItem> query)
        {
            IOrderedQueryable<LogScopeItem> orderedQuery = null;

            if (criteria.SortItems == null)
                return query;
            foreach (var sortItem in criteria.SortItems)
            {
                switch (sortItem.FieldName)
                {
                    case nameof(LogScopeItem.CreatedTime):
                        if (sortItem.Ascending)
                        {
                            if (orderedQuery != null)
                                orderedQuery = orderedQuery.ThenBy(o => o.CreatedTime);
                            else
                                orderedQuery = query.OrderBy(o => o.CreatedTime);
                        }
                        else
                        {
                            if (orderedQuery != null)
                                orderedQuery = orderedQuery.ThenByDescending(o => o.CreatedTime);
                            else
                                orderedQuery = query.OrderByDescending(o => o.CreatedTime);
                        }
                        break;
                    case nameof(LogScopeItem.Title):
                        if (sortItem.Ascending)
                        {
                            if (orderedQuery != null)
                                orderedQuery = orderedQuery.ThenBy(o => o.Title);
                            else
                                orderedQuery = query.OrderBy(o => o.Title);
                        }
                        else
                        {
                            if (orderedQuery != null)
                                orderedQuery = orderedQuery.ThenByDescending(o => o.Title);
                            else
                                orderedQuery = query.OrderByDescending(o => o.Title);
                        }
                        break;
                    default:
                        break;
                }
            }
            if (orderedQuery != null)
                return orderedQuery;
            return query;
        }

        #endregion

        #endregion
    }
}